package weaver.view;

import weaver.model.WeaverModel;
import weaver.controller.WeaverController;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

/**
 * GUI view for the Weaver game.
 * Implements the Observer pattern to receive updates from the model.
 */
public class WeaverGUIView extends JFrame implements Observer, WeaverView {
    private WeaverModel model;
    private WeaverController controller;
    
    private JLabel startWordLabel;
    private JLabel targetWordLabel;
    private JPanel wordGridPanel;
    private JPanel currentInputPanel;
    private JPanel keyboardPanel;
    private JButton resetButton;
    private JButton newGameButton;
    private JCheckBox showErrorCheckBox;
    private JCheckBox showPathCheckBox;
    private JCheckBox randomWordsCheckBox;
    private JPanel settingsPanel;
    
    private StringBuilder currentInput;
    private boolean hasShownWinMessage;  // 添加标志来跟踪是否已显示胜利消息
    
    // Color constants
    private static final Color PRIMARY_COLOR = new Color(41, 128, 185);
    private static final Color SECONDARY_COLOR = new Color(52, 152, 219);
    private static final Color SUCCESS_COLOR = new Color(34, 139, 34);
    private static final Color ERROR_COLOR = new Color(139, 0, 0);
    private static final Color BACKGROUND_COLOR = new Color(236, 240, 241);
    private static final Color TEXT_COLOR = Color.BLACK;

    // 三行面板
    private JPanel startPanel, inputPanel, targetPanel;

    public WeaverGUIView() {
        this.currentInput = new StringBuilder();

        // Set window properties
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Weaver Word Game");
        getContentPane().setBackground(BACKGROUND_COLOR);

        // Create main panel
        JPanel mainPanel = new JPanel(new BorderLayout(15, 15));
        mainPanel.setBackground(BACKGROUND_COLOR);
        mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        // Setup UI
        setupUI(mainPanel);

        // Add main panel to window
        add(mainPanel);

        // Add keyboard listener
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                char c = Character.toUpperCase(e.getKeyChar());
                if (Character.isLetter(c)) {
                    handleKeyPress(c);
                } else if (c == '\b') {
                    handleBackspace();
                } else if (c == '\n') {
                    handleEnter();
                }
            }
        });

        // Set window properties
        setFocusable(true);
        requestFocusInWindow();

        // Add focus listener
        addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                requestFocusInWindow();
            }
        });

        // Add mouse listener
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                requestFocusInWindow();
            }
        });

        // Set window size and position
        setMinimumSize(new Dimension(600, 600));
        pack();
        setLocationRelativeTo(null);
    }

    private void setupUI(JPanel mainPanel) {
        // Main content panel with vertical layout
        JPanel contentPanel = new JPanel();
        contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
        contentPanel.setBackground(BACKGROUND_COLOR);

        // Start word row
        startPanel = new JPanel(new GridLayout(1, 4, 8, 8));
        startPanel.setBackground(BACKGROUND_COLOR);
        contentPanel.add(startPanel);
        contentPanel.add(Box.createVerticalStrut(15));

        // Word grid panel (for showing entered words)
        wordGridPanel = new JPanel();
        wordGridPanel.setLayout(new BoxLayout(wordGridPanel, BoxLayout.Y_AXIS));
        wordGridPanel.setBackground(BACKGROUND_COLOR);
        JScrollPane scrollPane = new JScrollPane(wordGridPanel);
        scrollPane.setPreferredSize(new Dimension(500, 300));
        scrollPane.setBorder(BorderFactory.createEmptyBorder());
        scrollPane.getViewport().setBackground(BACKGROUND_COLOR);
        contentPanel.add(scrollPane);
        contentPanel.add(Box.createVerticalStrut(15));

        // Input row
        inputPanel = new JPanel(new GridLayout(1, 4, 8, 8));
        inputPanel.setBackground(BACKGROUND_COLOR);
        contentPanel.add(inputPanel);
        contentPanel.add(Box.createVerticalStrut(15));

        // Target word row
        targetPanel = new JPanel(new GridLayout(1, 4, 8, 8));
        targetPanel.setBackground(BACKGROUND_COLOR);
        contentPanel.add(targetPanel);
        contentPanel.add(Box.createVerticalStrut(15));

        // Add content panel to main panel
        mainPanel.add(contentPanel, BorderLayout.CENTER);

        // Bottom panel - Keyboard and controls
        JPanel bottomPanel = new JPanel(new BorderLayout(10, 10));
        bottomPanel.setBackground(BACKGROUND_COLOR);

        setupKeyboardPanel(bottomPanel);
        setupControlPanel(bottomPanel);

        mainPanel.add(bottomPanel, BorderLayout.SOUTH);
    }

    private JLabel createStyledLabel(String text) {
        JLabel label = new JLabel(text, SwingConstants.CENTER);
        label.setFont(new Font("Segoe UI", Font.BOLD, 20));
        label.setForeground(TEXT_COLOR);
        label.setBackground(BACKGROUND_COLOR);
        label.setOpaque(true);
        return label;
    }

    private JLabel createInputLabel(String text) {
        JLabel label = new JLabel(text, SwingConstants.CENTER);
        label.setFont(new Font("Segoe UI", Font.BOLD, 24));
        label.setForeground(TEXT_COLOR);
        label.setBackground(Color.WHITE);
        label.setOpaque(true);
        label.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(PRIMARY_COLOR, 2),
            BorderFactory.createEmptyBorder(3, 3, 3, 3)
        ));
        label.setPreferredSize(new Dimension(50, 50));
        return label;
    }

    private void setupKeyboardPanel(JPanel bottomPanel) {
        keyboardPanel = new JPanel(new GridLayout(4, 10, 3, 3));
        keyboardPanel.setBackground(BACKGROUND_COLOR);

        String[] letters = {
            "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P",
            "A", "S", "D", "F", "G", "H", "J", "K", "L",
            "Z", "X", "C", "V", "B", "N", "M"
        };

        // Create keyboard buttons
        for (String letter : letters) {
            JButton button = createKeyboardButton(letter);
            button.addActionListener(e -> handleKeyPress(letter.charAt(0)));
            keyboardPanel.add(button);
        }

        // Add function buttons
        JButton backspaceButton = createFunctionButton("Del", ERROR_COLOR);
        backspaceButton.addActionListener(e -> handleBackspace());
        keyboardPanel.add(backspaceButton);

        JButton enterButton = createFunctionButton("Enter", SUCCESS_COLOR);
        enterButton.addActionListener(e -> handleEnter());
        keyboardPanel.add(enterButton);

        bottomPanel.add(keyboardPanel, BorderLayout.CENTER);
    }

    private JButton createKeyboardButton(String text) {
        JButton button = new JButton(text);
        button.setFont(new Font("Segoe UI", Font.BOLD, 14));
        button.setForeground(TEXT_COLOR);
        button.setBackground(Color.WHITE);
        button.setFocusPainted(false);
        button.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(PRIMARY_COLOR, 1),
            BorderFactory.createEmptyBorder(2, 2, 2, 2)
        ));
        button.setPreferredSize(new Dimension(35, 35));
        return button;
    }

    private JButton createFunctionButton(String text, Color color) {
        JButton button = new JButton(text);
        button.setFont(new Font("Segoe UI", Font.BOLD, 14));
        button.setForeground(TEXT_COLOR);
        button.setBackground(color);
        button.setFocusPainted(false);
        button.setBorder(BorderFactory.createEmptyBorder(4, 8, 4, 8));
        button.setPreferredSize(new Dimension(50, 35));
        return button;
    }

    private JButton createControlButton(String text, Color color) {
        JButton button = new JButton(text);
        button.setFont(new Font("Segoe UI", Font.BOLD, 14));
        button.setForeground(TEXT_COLOR);
        button.setBackground(color);
        button.setFocusPainted(false);
        button.setBorder(BorderFactory.createEmptyBorder(8, 20, 8, 20));
        return button;
    }

    private JCheckBox createStyledCheckBox(String text) {
        JCheckBox checkBox = new JCheckBox(text);
        checkBox.setFont(new Font("Segoe UI", Font.PLAIN, 14));
        checkBox.setForeground(TEXT_COLOR);
        checkBox.setBackground(BACKGROUND_COLOR);
        checkBox.setFocusPainted(false);
        return checkBox;
    }

    private void setupControlPanel(JPanel bottomPanel) {
        JPanel controlPanel = new JPanel(new BorderLayout(10, 10));
        controlPanel.setBackground(BACKGROUND_COLOR);

        // Main buttons panel
        JPanel mainButtonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 10));
        mainButtonsPanel.setBackground(BACKGROUND_COLOR);

        resetButton = createControlButton("Reset", SECONDARY_COLOR);
        resetButton.setEnabled(false);
        resetButton.addActionListener(e -> {
            if (controller != null) {
                controller.resetGame();
                hasShownWinMessage = false;
            }
        });
        mainButtonsPanel.add(resetButton);

        newGameButton = createControlButton("New Game", PRIMARY_COLOR);
        newGameButton.addActionListener(e -> {
            if (controller == null) return;
            controller.setFlags(showErrorCheckBox.isSelected(),
                             showPathCheckBox.isSelected(),
                             randomWordsCheckBox.isSelected());
            controller.startGame(null, null);
            currentInput.setLength(0);
            hasShownWinMessage = false;  // 重置胜利消息标志
            updateDisplay();
            startPanel.revalidate();
            startPanel.repaint();
            targetPanel.revalidate();
            targetPanel.repaint();
        });
        mainButtonsPanel.add(newGameButton);

        JButton settingsButton = createControlButton("Settings", SECONDARY_COLOR);
        settingsButton.addActionListener(e -> {
            settingsPanel.setVisible(!settingsPanel.isVisible());
            controlPanel.revalidate();
            controlPanel.repaint();
        });
        mainButtonsPanel.add(settingsButton);

        controlPanel.add(mainButtonsPanel, BorderLayout.NORTH);

        // Settings panel
        settingsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 10));
        settingsPanel.setBackground(BACKGROUND_COLOR);
        settingsPanel.setVisible(false);

        showErrorCheckBox = createStyledCheckBox("Show Errors");
        showPathCheckBox = createStyledCheckBox("Show Path");
        randomWordsCheckBox = createStyledCheckBox("Random Words");

        // Set initial checkbox states
        showErrorCheckBox.setSelected(true);
        showPathCheckBox.setSelected(false);
        randomWordsCheckBox.setSelected(false);

        // Add action listeners to checkboxes
        showErrorCheckBox.addActionListener(e -> {
            if (controller != null) {
                controller.setFlags(showErrorCheckBox.isSelected(),
                                 showPathCheckBox.isSelected(),
                                 randomWordsCheckBox.isSelected());
                updateDisplay();
            }
        });

        showPathCheckBox.addActionListener(e -> {
            if (controller != null) {
                controller.setFlags(showErrorCheckBox.isSelected(),
                                 showPathCheckBox.isSelected(),
                                 randomWordsCheckBox.isSelected());
                updateDisplay();
            }
        });

        randomWordsCheckBox.addActionListener(e -> {
            if (controller != null) {
                controller.setFlags(showErrorCheckBox.isSelected(),
                                 showPathCheckBox.isSelected(),
                                 randomWordsCheckBox.isSelected());
                updateDisplay();
            }
        });

        settingsPanel.add(showErrorCheckBox);
        settingsPanel.add(showPathCheckBox);
        settingsPanel.add(randomWordsCheckBox);

        controlPanel.add(settingsPanel, BorderLayout.CENTER);
        bottomPanel.add(controlPanel, BorderLayout.SOUTH);
    }

    private void addWordToGrid(String word, boolean isSolution) {
        JPanel wordPanel = new JPanel(new GridLayout(1, 4, 5, 5));
        wordPanel.setBackground(BACKGROUND_COLOR);

        boolean[] status = checkLetterCorrectness(word);
        for (int i = 0; i < 4; i++) {
            JLabel label = new JLabel(String.valueOf(word.charAt(i)), SwingConstants.CENTER);
            label.setFont(new Font("Segoe UI", Font.BOLD, 20));
            label.setOpaque(true);
            label.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(isSolution ? SECONDARY_COLOR : PRIMARY_COLOR, 2),
                BorderFactory.createEmptyBorder(3, 3, 3, 3)
            ));
            label.setPreferredSize(new Dimension(50, 50));

            if (status[i]) {
                label.setBackground(SUCCESS_COLOR);
                label.setForeground(Color.WHITE);
            } else {
                label.setBackground(isSolution ? new Color(200, 200, 255) : Color.WHITE);
                label.setForeground(TEXT_COLOR);
            }
            wordPanel.add(label);
        }
        wordGridPanel.add(wordPanel);
        wordGridPanel.add(Box.createVerticalStrut(8));
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o == model) {
            updateDisplay();
        }
    }

    @Override
    public void showError(String message) {
        JOptionPane.showMessageDialog(this, message, "Error", JOptionPane.ERROR_MESSAGE);
    }

    @Override
    public void showSuccess(String message) {
        JOptionPane.showMessageDialog(this, message, "Success", JOptionPane.INFORMATION_MESSAGE);
    }

    @Override
    public void updateDisplay() {
        assert model != null : "Model should not be null when updating display";

        // 刷新 startPanel
        startPanel.removeAll();
        String start = model.getStartWord().toUpperCase();
        assert start.length() == 4 : "Start word must be 4 characters long";
        for (int i = 0; i < 4; i++) {
            startPanel.add(createInputLabel(String.valueOf(start.charAt(i))));
        }

        // 刷新 inputPanel
        inputPanel.removeAll();
        for (int i = 0; i < 4; i++) {
            char c = (i < currentInput.length()) ? currentInput.charAt(i) : ' ';
            inputPanel.add(createInputLabel(c == ' ' ? "" : String.valueOf(c)));
        }

        // 刷新 targetPanel
        targetPanel.removeAll();
        String target = model.getTargetWord().toUpperCase();
        assert target.length() == 4 : "Target word must be 4 characters long";
        for (int i = 0; i < 4; i++) {
            char targetChar = target.charAt(i);
            boolean match = i < currentInput.length() &&
                    Character.toUpperCase(currentInput.charAt(i)) == targetChar;

            JLabel label = new JLabel(String.valueOf(targetChar), SwingConstants.CENTER);
            label.setFont(new Font("Segoe UI", Font.BOLD, 24));
            label.setForeground(TEXT_COLOR);
            label.setOpaque(true);
            label.setBorder(BorderFactory.createCompoundBorder(
                    BorderFactory.createLineBorder(PRIMARY_COLOR, 2),
                    BorderFactory.createEmptyBorder(3, 3, 3, 3)
            ));
            label.setPreferredSize(new Dimension(50, 50));

            if (match) {
                label.setBackground(SUCCESS_COLOR);
                label.setForeground(Color.WHITE);
            } else {
                label.setBackground(Color.WHITE);
            }

            targetPanel.add(label);
        }


        // Update word grid (entered words) - 只显示已输入的单词，不包括start word
        wordGridPanel.removeAll();
        List<String> path = model.getCurrentPath();
        assert path != null : "Path should not be null";
        // 跳过第一个单词（start word），因为它已经在startPanel中显示了
        for (int i = 1; i < path.size(); i++) {
            addWordToGrid(path.get(i), false);
        }

        // Add solution path if enabled
        if (model.isShowingPath()) {
            List<String> solutionPath = model.getSolutionPath();
            if (solutionPath != null && !solutionPath.isEmpty()) {
                JPanel separator = new JPanel();
                separator.setPreferredSize(new Dimension(500, 2));
                separator.setBackground(SECONDARY_COLOR);
                wordGridPanel.add(separator);
                // 跳过第一个单词（start word）
                for (int i = 1; i < solutionPath.size(); i++) {
                    addWordToGrid(solutionPath.get(i), true);
                }
            }
        }

        resetButton.setEnabled(path.size() > 1);
        wordGridPanel.revalidate();
        wordGridPanel.repaint();

        if (model.isGameWon() && path.size() > 1 && !path.get(0).equals(path.get(path.size() - 1)) && !hasShownWinMessage) {
            showSuccess("Congratulations! You won!");
            hasShownWinMessage = true;
        }
    }

    public void setModel(WeaverModel model) {
        this.model = model;
    }

    public void setController(WeaverController controller) {
        this.controller = controller;
    }

    private void handleKeyPress(char c) {
        if (currentInput.length() < 4) {
            currentInput.append(c);
            updateCurrentInputDisplay();
        }
    }

    private void handleBackspace() {
        if (currentInput.length() > 0) {
            currentInput.deleteCharAt(currentInput.length() - 1);
            updateCurrentInputDisplay();
        }
    }

    private void handleEnter() {
        if (currentInput.length() == 4 && controller != null) {
            controller.handleInput(currentInput.toString());
            currentInput.setLength(0);
            updateCurrentInputDisplay();
        }
    }

    private void updateCurrentInputDisplay() {
        inputPanel.removeAll();
        for (int i = 0; i < 4; i++) {
            char c = (i < currentInput.length()) ? currentInput.charAt(i) : ' ';
            inputPanel.add(createInputLabel(c == ' ' ? "" : String.valueOf(c)));
        }
        inputPanel.revalidate();
        inputPanel.repaint();
    }
    
    private boolean[] checkLetterCorrectness(String word) {
        String target = model.getTargetWord();
        if (target == null) return new boolean[4];
        
        boolean[] result = new boolean[4];
        for (int i = 0; i < 4; i++) {
            result[i] = Character.toLowerCase(word.charAt(i)) == Character.toLowerCase(target.charAt(i));
        }
        return result;
    }
}